#include "M6502.h"
#include <stdio.h>
#include <stdlib.h>
#include "Commons.h"
#include <string.h>

////////////////////////////////////////////////////////////////////////////////////////////////////

M6502::M6502() {
    m_Reg.A = 0;
    m_Reg.X = 0;
    m_Reg.Y = 0;
    m_SP = 0xfd;
    m_Flag.N = false;
    m_Flag.V = false;
    m_Flag.P = true;
    m_Flag.B = false;
    m_Flag.D = false;
    m_Flag.I = true;
    m_Flag.Z = false;
    m_Flag.C = false;
    m_Cycles = 0;

    m_OPFunc[ 0x01 ] = &M6502::OP_ORA; m_OPMode[ 0x01 ] = INX;    m_OPCycles[ 0x01 ] = 6; m_OPName[ 0x01 ] = "ORA";
    m_OPFunc[ 0x05 ] = &M6502::OP_ORA; m_OPMode[ 0x05 ] = ZP;     m_OPCycles[ 0x05 ] = 3; m_OPName[ 0x05 ] = "ORA";
    m_OPFunc[ 0x06 ] = &M6502::OP_ASL; m_OPMode[ 0x06 ] = ZP;     m_OPCycles[ 0x06 ] = 5; m_OPName[ 0x06 ] = "ASL";
    m_OPFunc[ 0x08 ] = &M6502::OP_PHP; m_OPMode[ 0x08 ] = IMP;    m_OPCycles[ 0x08 ] = 3; m_OPName[ 0x08 ] = "PHP";
    m_OPFunc[ 0x09 ] = &M6502::OP_ORA; m_OPMode[ 0x09 ] = IMM;    m_OPCycles[ 0x09 ] = 2; m_OPName[ 0x09 ] = "ORA";
    m_OPFunc[ 0x0a ] = &M6502::OP_ASL; m_OPMode[ 0x0a ] = ACC;    m_OPCycles[ 0x0a ] = 2; m_OPName[ 0x0a ] = "ASL";
    m_OPFunc[ 0x0d ] = &M6502::OP_ORA; m_OPMode[ 0x0d ] = ABS;    m_OPCycles[ 0x0d ] = 4; m_OPName[ 0x0d ] = "ORA";
    m_OPFunc[ 0x0e ] = &M6502::OP_ASL; m_OPMode[ 0x0e ] = ABS;    m_OPCycles[ 0x0e ] = 6; m_OPName[ 0x0e ] = "ASL";
    m_OPFunc[ 0x10 ] = &M6502::OP_BPL; m_OPMode[ 0x10 ] = REL;    m_OPCycles[ 0x10 ] = 2; m_OPName[ 0x10 ] = "BPL";
    m_OPFunc[ 0x11 ] = &M6502::OP_ORA; m_OPMode[ 0x11 ] = INY;    m_OPCycles[ 0x11 ] = 5; m_OPName[ 0x11 ] = "ORA";
    m_OPFunc[ 0x15 ] = &M6502::OP_ORA; m_OPMode[ 0x15 ] = ZPX;    m_OPCycles[ 0x15 ] = 4; m_OPName[ 0x15 ] = "ORA";
    m_OPFunc[ 0x16 ] = &M6502::OP_ASL; m_OPMode[ 0x16 ] = ZPX;    m_OPCycles[ 0x16 ] = 6; m_OPName[ 0x16 ] = "ASL";
    m_OPFunc[ 0x18 ] = &M6502::OP_CLC; m_OPMode[ 0x18 ] = IMP;    m_OPCycles[ 0x18 ] = 2; m_OPName[ 0x18 ] = "CLC";
    m_OPFunc[ 0x19 ] = &M6502::OP_ORA; m_OPMode[ 0x19 ] = ABY;    m_OPCycles[ 0x19 ] = 4; m_OPName[ 0x19 ] = "ORA";
    m_OPFunc[ 0x1d ] = &M6502::OP_ORA; m_OPMode[ 0x1d ] = ABX;    m_OPCycles[ 0x1d ] = 4; m_OPName[ 0x1d ] = "ORA";
    m_OPFunc[ 0x1e ] = &M6502::OP_ASL; m_OPMode[ 0x1e ] = ABX_NC; m_OPCycles[ 0x1e ] = 7; m_OPName[ 0x1e ] = "ASL";
    m_OPFunc[ 0x20 ] = &M6502::OP_JSR; m_OPMode[ 0x20 ] = ABS;    m_OPCycles[ 0x20 ] = 6; m_OPName[ 0x20 ] = "JSR";
    m_OPFunc[ 0x21 ] = &M6502::OP_AND; m_OPMode[ 0x21 ] = INX;    m_OPCycles[ 0x21 ] = 6; m_OPName[ 0x21 ] = "AND";
    m_OPFunc[ 0x24 ] = &M6502::OP_BIT; m_OPMode[ 0x24 ] = ZP;     m_OPCycles[ 0x24 ] = 3; m_OPName[ 0x24 ] = "BIT";
    m_OPFunc[ 0x25 ] = &M6502::OP_AND; m_OPMode[ 0x25 ] = ZP;     m_OPCycles[ 0x25 ] = 3; m_OPName[ 0x25 ] = "AND";
    m_OPFunc[ 0x26 ] = &M6502::OP_ROL; m_OPMode[ 0x26 ] = ZP;     m_OPCycles[ 0x26 ] = 5; m_OPName[ 0x26 ] = "ROL";
    m_OPFunc[ 0x28 ] = &M6502::OP_PLP; m_OPMode[ 0x28 ] = IMP;    m_OPCycles[ 0x28 ] = 4; m_OPName[ 0x28 ] = "PLP";
    m_OPFunc[ 0x29 ] = &M6502::OP_AND; m_OPMode[ 0x29 ] = IMM;    m_OPCycles[ 0x29 ] = 2; m_OPName[ 0x29 ] = "AND";
    m_OPFunc[ 0x2a ] = &M6502::OP_ROL; m_OPMode[ 0x2a ] = ACC;    m_OPCycles[ 0x2a ] = 2; m_OPName[ 0x2a ] = "ROL";
    m_OPFunc[ 0x2c ] = &M6502::OP_BIT; m_OPMode[ 0x2c ] = ABS;    m_OPCycles[ 0x2c ] = 4; m_OPName[ 0x2c ] = "BIT";
    m_OPFunc[ 0x2d ] = &M6502::OP_AND; m_OPMode[ 0x2d ] = ABS;    m_OPCycles[ 0x2d ] = 4; m_OPName[ 0x2d ] = "AND";
    m_OPFunc[ 0x2e ] = &M6502::OP_ROL; m_OPMode[ 0x2e ] = ABS;    m_OPCycles[ 0x2e ] = 6; m_OPName[ 0x2e ] = "ROL";
    m_OPFunc[ 0x30 ] = &M6502::OP_BMI; m_OPMode[ 0x30 ] = REL;    m_OPCycles[ 0x30 ] = 2; m_OPName[ 0x30 ] = "BMI";
    m_OPFunc[ 0x31 ] = &M6502::OP_AND; m_OPMode[ 0x31 ] = INY;    m_OPCycles[ 0x31 ] = 5; m_OPName[ 0x31 ] = "AND";
    m_OPFunc[ 0x35 ] = &M6502::OP_AND; m_OPMode[ 0x35 ] = ZPX;    m_OPCycles[ 0x35 ] = 4; m_OPName[ 0x35 ] = "AND";
    m_OPFunc[ 0x36 ] = &M6502::OP_ROL; m_OPMode[ 0x36 ] = ZPX;    m_OPCycles[ 0x36 ] = 6; m_OPName[ 0x36 ] = "ROL";
    m_OPFunc[ 0x38 ] = &M6502::OP_SEC; m_OPMode[ 0x38 ] = IMP;    m_OPCycles[ 0x38 ] = 2; m_OPName[ 0x38 ] = "SEC";
    m_OPFunc[ 0x39 ] = &M6502::OP_AND; m_OPMode[ 0x39 ] = ABY;    m_OPCycles[ 0x39 ] = 4; m_OPName[ 0x39 ] = "AND";
    m_OPFunc[ 0x3d ] = &M6502::OP_AND; m_OPMode[ 0x3d ] = ABX;    m_OPCycles[ 0x3d ] = 4; m_OPName[ 0x3d ] = "AND";
    m_OPFunc[ 0x3e ] = &M6502::OP_ROL; m_OPMode[ 0x3e ] = ABX_NC; m_OPCycles[ 0x3e ] = 7; m_OPName[ 0x3e ] = "ROL";
    m_OPFunc[ 0x40 ] = &M6502::OP_RTI; m_OPMode[ 0x40 ] = IMP;    m_OPCycles[ 0x40 ] = 6; m_OPName[ 0x40 ] = "RTI";
    m_OPFunc[ 0x41 ] = &M6502::OP_EOR; m_OPMode[ 0x41 ] = INX;    m_OPCycles[ 0x41 ] = 6; m_OPName[ 0x41 ] = "EOR";
    m_OPFunc[ 0x45 ] = &M6502::OP_EOR; m_OPMode[ 0x45 ] = ZP;     m_OPCycles[ 0x45 ] = 3; m_OPName[ 0x45 ] = "EOR";
    m_OPFunc[ 0x46 ] = &M6502::OP_LSR; m_OPMode[ 0x46 ] = ZP;     m_OPCycles[ 0x46 ] = 5; m_OPName[ 0x46 ] = "LSR";
    m_OPFunc[ 0x48 ] = &M6502::OP_PHA; m_OPMode[ 0x48 ] = IMP;    m_OPCycles[ 0x48 ] = 3; m_OPName[ 0x48 ] = "PHA";
    m_OPFunc[ 0x49 ] = &M6502::OP_EOR; m_OPMode[ 0x49 ] = IMM;    m_OPCycles[ 0x49 ] = 2; m_OPName[ 0x49 ] = "EOR";
    m_OPFunc[ 0x4a ] = &M6502::OP_LSR; m_OPMode[ 0x4a ] = ACC;    m_OPCycles[ 0x4a ] = 2; m_OPName[ 0x4a ] = "LSR";
    m_OPFunc[ 0x4c ] = &M6502::OP_JMP; m_OPMode[ 0x4c ] = ABS;    m_OPCycles[ 0x4c ] = 3; m_OPName[ 0x4c ] = "JMP";
    m_OPFunc[ 0x4d ] = &M6502::OP_EOR; m_OPMode[ 0x4d ] = ABS;    m_OPCycles[ 0x4d ] = 4; m_OPName[ 0x4d ] = "EOR";
    m_OPFunc[ 0x4e ] = &M6502::OP_LSR; m_OPMode[ 0x4e ] = ABS;    m_OPCycles[ 0x4e ] = 6; m_OPName[ 0x4e ] = "LSR";
    m_OPFunc[ 0x50 ] = &M6502::OP_BVC; m_OPMode[ 0x50 ] = REL;    m_OPCycles[ 0x50 ] = 2; m_OPName[ 0x50 ] = "BVC";
    m_OPFunc[ 0x51 ] = &M6502::OP_EOR; m_OPMode[ 0x51 ] = INY;    m_OPCycles[ 0x51 ] = 5; m_OPName[ 0x51 ] = "EOR";
    m_OPFunc[ 0x55 ] = &M6502::OP_EOR; m_OPMode[ 0x55 ] = ZPX;    m_OPCycles[ 0x55 ] = 4; m_OPName[ 0x55 ] = "EOR";
    m_OPFunc[ 0x56 ] = &M6502::OP_LSR; m_OPMode[ 0x56 ] = ZPX;    m_OPCycles[ 0x56 ] = 6; m_OPName[ 0x56 ] = "LSR";
    m_OPFunc[ 0x58 ] = &M6502::OP_CLI; m_OPMode[ 0x58 ] = IMP;    m_OPCycles[ 0x58 ] = 2; m_OPName[ 0x58 ] = "CLI";
    m_OPFunc[ 0x59 ] = &M6502::OP_EOR; m_OPMode[ 0x59 ] = ABY;    m_OPCycles[ 0x59 ] = 4; m_OPName[ 0x59 ] = "EOR";
    m_OPFunc[ 0x5d ] = &M6502::OP_EOR; m_OPMode[ 0x5d ] = ABX;    m_OPCycles[ 0x5d ] = 4; m_OPName[ 0x5d ] = "EOR";
    m_OPFunc[ 0x5e ] = &M6502::OP_LSR; m_OPMode[ 0x5e ] = ABX_NC; m_OPCycles[ 0x5e ] = 7; m_OPName[ 0x5e ] = "LSR";
    m_OPFunc[ 0x60 ] = &M6502::OP_RTS; m_OPMode[ 0x60 ] = IMP;    m_OPCycles[ 0x60 ] = 6; m_OPName[ 0x60 ] = "RTS";
    m_OPFunc[ 0x61 ] = &M6502::OP_ADC; m_OPMode[ 0x61 ] = INX;    m_OPCycles[ 0x61 ] = 6; m_OPName[ 0x61 ] = "ADC";
    m_OPFunc[ 0x65 ] = &M6502::OP_ADC; m_OPMode[ 0x65 ] = ZP;     m_OPCycles[ 0x65 ] = 3; m_OPName[ 0x65 ] = "ADC";
    m_OPFunc[ 0x66 ] = &M6502::OP_ROR; m_OPMode[ 0x66 ] = ZP;     m_OPCycles[ 0x66 ] = 5; m_OPName[ 0x66 ] = "ROR";
    m_OPFunc[ 0x68 ] = &M6502::OP_PLA; m_OPMode[ 0x68 ] = IMP;    m_OPCycles[ 0x68 ] = 4; m_OPName[ 0x68 ] = "PLA";
    m_OPFunc[ 0x69 ] = &M6502::OP_ADC; m_OPMode[ 0x69 ] = IMM;    m_OPCycles[ 0x69 ] = 2; m_OPName[ 0x69 ] = "ADC";
    m_OPFunc[ 0x6a ] = &M6502::OP_ROR; m_OPMode[ 0x6a ] = ACC;    m_OPCycles[ 0x6a ] = 2; m_OPName[ 0x6a ] = "ROR";
    m_OPFunc[ 0x6c ] = &M6502::OP_JMP; m_OPMode[ 0x6c ] = IND;    m_OPCycles[ 0x6c ] = 5; m_OPName[ 0x6c ] = "JMP";
    m_OPFunc[ 0x6d ] = &M6502::OP_ADC; m_OPMode[ 0x6d ] = ABS;    m_OPCycles[ 0x6d ] = 4; m_OPName[ 0x6d ] = "ADC";
    m_OPFunc[ 0x6e ] = &M6502::OP_ROR; m_OPMode[ 0x6e ] = ABS;    m_OPCycles[ 0x6e ] = 6; m_OPName[ 0x6e ] = "ROR";
    m_OPFunc[ 0x70 ] = &M6502::OP_BVS; m_OPMode[ 0x70 ] = REL;    m_OPCycles[ 0x70 ] = 2; m_OPName[ 0x70 ] = "BVS";
    m_OPFunc[ 0x71 ] = &M6502::OP_ADC; m_OPMode[ 0x71 ] = INY;    m_OPCycles[ 0x71 ] = 5; m_OPName[ 0x71 ] = "ADC";
    m_OPFunc[ 0x75 ] = &M6502::OP_ADC; m_OPMode[ 0x75 ] = ZPX;    m_OPCycles[ 0x75 ] = 4; m_OPName[ 0x75 ] = "ADC";
    m_OPFunc[ 0x76 ] = &M6502::OP_ROR; m_OPMode[ 0x76 ] = ZPX;    m_OPCycles[ 0x76 ] = 6; m_OPName[ 0x76 ] = "ROR";
    m_OPFunc[ 0x78 ] = &M6502::OP_SEI; m_OPMode[ 0x78 ] = IMP;    m_OPCycles[ 0x78 ] = 2; m_OPName[ 0x78 ] = "SEI";
    m_OPFunc[ 0x79 ] = &M6502::OP_ADC; m_OPMode[ 0x79 ] = ABY;    m_OPCycles[ 0x79 ] = 4; m_OPName[ 0x79 ] = "ADC";
    m_OPFunc[ 0x7d ] = &M6502::OP_ADC; m_OPMode[ 0x7d ] = ABX;    m_OPCycles[ 0x7d ] = 4; m_OPName[ 0x7d ] = "ADC";
    m_OPFunc[ 0x7e ] = &M6502::OP_ROR; m_OPMode[ 0x7e ] = ABX_NC; m_OPCycles[ 0x7e ] = 7; m_OPName[ 0x7e ] = "ROR";
    m_OPFunc[ 0x81 ] = &M6502::OP_STA; m_OPMode[ 0x81 ] = INX;    m_OPCycles[ 0x81 ] = 6; m_OPName[ 0x81 ] = "STA";
    m_OPFunc[ 0x84 ] = &M6502::OP_STY; m_OPMode[ 0x84 ] = ZP;     m_OPCycles[ 0x84 ] = 3; m_OPName[ 0x84 ] = "STY";
    m_OPFunc[ 0x85 ] = &M6502::OP_STA; m_OPMode[ 0x85 ] = ZP;     m_OPCycles[ 0x85 ] = 3; m_OPName[ 0x85 ] = "STA";
    m_OPFunc[ 0x86 ] = &M6502::OP_STX; m_OPMode[ 0x86 ] = ZP;     m_OPCycles[ 0x86 ] = 3; m_OPName[ 0x86 ] = "STX";
    m_OPFunc[ 0x88 ] = &M6502::OP_DEY; m_OPMode[ 0x88 ] = IMP;    m_OPCycles[ 0x88 ] = 2; m_OPName[ 0x88 ] = "DEY";
    m_OPFunc[ 0x8a ] = &M6502::OP_TXA; m_OPMode[ 0x8a ] = IMP;    m_OPCycles[ 0x8a ] = 2; m_OPName[ 0x8a ] = "TXA";
    m_OPFunc[ 0x8c ] = &M6502::OP_STY; m_OPMode[ 0x8c ] = ABS;    m_OPCycles[ 0x8c ] = 4; m_OPName[ 0x8c ] = "STY";
    m_OPFunc[ 0x8d ] = &M6502::OP_STA; m_OPMode[ 0x8d ] = ABS;    m_OPCycles[ 0x8d ] = 4; m_OPName[ 0x8d ] = "STA";
    m_OPFunc[ 0x8e ] = &M6502::OP_STX; m_OPMode[ 0x8e ] = ABS;    m_OPCycles[ 0x8e ] = 4; m_OPName[ 0x8e ] = "STX";
    m_OPFunc[ 0x90 ] = &M6502::OP_BCC; m_OPMode[ 0x90 ] = REL;    m_OPCycles[ 0x90 ] = 2; m_OPName[ 0x90 ] = "BCC";
    m_OPFunc[ 0x91 ] = &M6502::OP_STA; m_OPMode[ 0x91 ] = INY_NC; m_OPCycles[ 0x91 ] = 6; m_OPName[ 0x91 ] = "STA";
    m_OPFunc[ 0x94 ] = &M6502::OP_STY; m_OPMode[ 0x94 ] = ZPX;    m_OPCycles[ 0x94 ] = 4; m_OPName[ 0x94 ] = "STY";
    m_OPFunc[ 0x95 ] = &M6502::OP_STA; m_OPMode[ 0x95 ] = ZPX;    m_OPCycles[ 0x95 ] = 4; m_OPName[ 0x95 ] = "STA";
    m_OPFunc[ 0x96 ] = &M6502::OP_STX; m_OPMode[ 0x96 ] = ZPY;    m_OPCycles[ 0x96 ] = 4; m_OPName[ 0x96 ] = "STX";
    m_OPFunc[ 0x98 ] = &M6502::OP_TYA; m_OPMode[ 0x98 ] = IMP;    m_OPCycles[ 0x98 ] = 2; m_OPName[ 0x98 ] = "TYA";
    m_OPFunc[ 0x99 ] = &M6502::OP_STA; m_OPMode[ 0x99 ] = ABY_NC; m_OPCycles[ 0x99 ] = 5; m_OPName[ 0x99 ] = "STA";
    m_OPFunc[ 0x9a ] = &M6502::OP_TXS; m_OPMode[ 0x9a ] = IMP;    m_OPCycles[ 0x9a ] = 2; m_OPName[ 0x9a ] = "TXS";
    m_OPFunc[ 0x9d ] = &M6502::OP_STA; m_OPMode[ 0x9d ] = ABX_NC; m_OPCycles[ 0x9d ] = 5; m_OPName[ 0x9d ] = "STA";
    m_OPFunc[ 0xa0 ] = &M6502::OP_LDY; m_OPMode[ 0xa0 ] = IMM;    m_OPCycles[ 0xa0 ] = 2; m_OPName[ 0xa0 ] = "LDY";
    m_OPFunc[ 0xa1 ] = &M6502::OP_LDA; m_OPMode[ 0xa1 ] = INX;    m_OPCycles[ 0xa1 ] = 6; m_OPName[ 0xa1 ] = "LDA";
    m_OPFunc[ 0xa2 ] = &M6502::OP_LDX; m_OPMode[ 0xa2 ] = IMM;    m_OPCycles[ 0xa2 ] = 2; m_OPName[ 0xa2 ] = "LDX";
    m_OPFunc[ 0xa4 ] = &M6502::OP_LDY; m_OPMode[ 0xa4 ] = ZP;     m_OPCycles[ 0xa4 ] = 3; m_OPName[ 0xa4 ] = "LDY";
    m_OPFunc[ 0xa5 ] = &M6502::OP_LDA; m_OPMode[ 0xa5 ] = ZP;     m_OPCycles[ 0xa5 ] = 3; m_OPName[ 0xa5 ] = "LDA";
    m_OPFunc[ 0xa6 ] = &M6502::OP_LDX; m_OPMode[ 0xa6 ] = ZP;     m_OPCycles[ 0xa6 ] = 3; m_OPName[ 0xa6 ] = "LDX";
    m_OPFunc[ 0xa8 ] = &M6502::OP_TAY; m_OPMode[ 0xa8 ] = IMP;    m_OPCycles[ 0xa8 ] = 2; m_OPName[ 0xa8 ] = "TAY";
    m_OPFunc[ 0xa9 ] = &M6502::OP_LDA; m_OPMode[ 0xa9 ] = IMM;    m_OPCycles[ 0xa9 ] = 2; m_OPName[ 0xa9 ] = "LDA";
    m_OPFunc[ 0xaa ] = &M6502::OP_TAX; m_OPMode[ 0xaa ] = IMP;    m_OPCycles[ 0xaa ] = 2; m_OPName[ 0xaa ] = "TAX";
    m_OPFunc[ 0xac ] = &M6502::OP_LDY; m_OPMode[ 0xac ] = ABS;    m_OPCycles[ 0xac ] = 4; m_OPName[ 0xac ] = "LDY";
    m_OPFunc[ 0xad ] = &M6502::OP_LDA; m_OPMode[ 0xad ] = ABS;    m_OPCycles[ 0xad ] = 4; m_OPName[ 0xad ] = "LDA";
    m_OPFunc[ 0xae ] = &M6502::OP_LDX; m_OPMode[ 0xae ] = ABS;    m_OPCycles[ 0xae ] = 4; m_OPName[ 0xae ] = "LDX";
    m_OPFunc[ 0xb0 ] = &M6502::OP_BCS; m_OPMode[ 0xb0 ] = REL;    m_OPCycles[ 0xb0 ] = 2; m_OPName[ 0xb0 ] = "BCS";
    m_OPFunc[ 0xb1 ] = &M6502::OP_LDA; m_OPMode[ 0xb1 ] = INY;    m_OPCycles[ 0xb1 ] = 5; m_OPName[ 0xb1 ] = "LDA";
    m_OPFunc[ 0xb4 ] = &M6502::OP_LDY; m_OPMode[ 0xb4 ] = ZPX;    m_OPCycles[ 0xb4 ] = 4; m_OPName[ 0xb4 ] = "LDY";
    m_OPFunc[ 0xb5 ] = &M6502::OP_LDA; m_OPMode[ 0xb5 ] = ZPX;    m_OPCycles[ 0xb5 ] = 4; m_OPName[ 0xb5 ] = "LDA";
    m_OPFunc[ 0xb6 ] = &M6502::OP_LDX; m_OPMode[ 0xb6 ] = ZPY;    m_OPCycles[ 0xb6 ] = 4; m_OPName[ 0xb6 ] = "LDX";
    m_OPFunc[ 0xb8 ] = &M6502::OP_CLV; m_OPMode[ 0xb8 ] = IMP;    m_OPCycles[ 0xb8 ] = 2; m_OPName[ 0xb8 ] = "CLV";
    m_OPFunc[ 0xb9 ] = &M6502::OP_LDA; m_OPMode[ 0xb9 ] = ABY;    m_OPCycles[ 0xb9 ] = 4; m_OPName[ 0xb9 ] = "LDA";
    m_OPFunc[ 0xba ] = &M6502::OP_TSX; m_OPMode[ 0xba ] = IMP;    m_OPCycles[ 0xba ] = 2; m_OPName[ 0xba ] = "TSX";
    m_OPFunc[ 0xbc ] = &M6502::OP_LDY; m_OPMode[ 0xbc ] = ABX;    m_OPCycles[ 0xbc ] = 4; m_OPName[ 0xbc ] = "LDY";
    m_OPFunc[ 0xbd ] = &M6502::OP_LDA; m_OPMode[ 0xbd ] = ABX;    m_OPCycles[ 0xbd ] = 4; m_OPName[ 0xbd ] = "LDA";
    m_OPFunc[ 0xbe ] = &M6502::OP_LDX; m_OPMode[ 0xbe ] = ABY;    m_OPCycles[ 0xbe ] = 4; m_OPName[ 0xbe ] = "LDX";
    m_OPFunc[ 0xc0 ] = &M6502::OP_CPY; m_OPMode[ 0xc0 ] = IMM;    m_OPCycles[ 0xc0 ] = 2; m_OPName[ 0xc0 ] = "CPY";
    m_OPFunc[ 0xc1 ] = &M6502::OP_CMP; m_OPMode[ 0xc1 ] = INX;    m_OPCycles[ 0xc1 ] = 6; m_OPName[ 0xc1 ] = "CMP";
    m_OPFunc[ 0xc4 ] = &M6502::OP_CPY; m_OPMode[ 0xc4 ] = ZP;     m_OPCycles[ 0xc4 ] = 3; m_OPName[ 0xc4 ] = "CPY";
    m_OPFunc[ 0xc5 ] = &M6502::OP_CMP; m_OPMode[ 0xc5 ] = ZP;     m_OPCycles[ 0xc5 ] = 3; m_OPName[ 0xc5 ] = "CMP";
    m_OPFunc[ 0xc6 ] = &M6502::OP_DEC; m_OPMode[ 0xc6 ] = ZP;     m_OPCycles[ 0xc6 ] = 5; m_OPName[ 0xc6 ] = "DEC";
    m_OPFunc[ 0xc8 ] = &M6502::OP_INY; m_OPMode[ 0xc8 ] = IMP;    m_OPCycles[ 0xc8 ] = 2; m_OPName[ 0xc8 ] = "INY";
    m_OPFunc[ 0xc9 ] = &M6502::OP_CMP; m_OPMode[ 0xc9 ] = IMM;    m_OPCycles[ 0xc9 ] = 2; m_OPName[ 0xc9 ] = "CMP";
    m_OPFunc[ 0xca ] = &M6502::OP_DEX; m_OPMode[ 0xca ] = IMP;    m_OPCycles[ 0xca ] = 2; m_OPName[ 0xca ] = "DEX";
    m_OPFunc[ 0xcc ] = &M6502::OP_CPY; m_OPMode[ 0xcc ] = ABS;    m_OPCycles[ 0xcc ] = 4; m_OPName[ 0xcc ] = "CPY";
    m_OPFunc[ 0xcd ] = &M6502::OP_CMP; m_OPMode[ 0xcd ] = ABS;    m_OPCycles[ 0xcd ] = 4; m_OPName[ 0xcd ] = "CMP";
    m_OPFunc[ 0xce ] = &M6502::OP_DEC; m_OPMode[ 0xce ] = ABS;    m_OPCycles[ 0xce ] = 6; m_OPName[ 0xce ] = "DEC";
    m_OPFunc[ 0xd0 ] = &M6502::OP_BNE; m_OPMode[ 0xd0 ] = REL;    m_OPCycles[ 0xd0 ] = 2; m_OPName[ 0xd0 ] = "BNE";
    m_OPFunc[ 0xd1 ] = &M6502::OP_CMP; m_OPMode[ 0xd1 ] = INY;    m_OPCycles[ 0xd1 ] = 5; m_OPName[ 0xd1 ] = "CMP";
    m_OPFunc[ 0xd5 ] = &M6502::OP_CMP; m_OPMode[ 0xd5 ] = ZPX;    m_OPCycles[ 0xd5 ] = 4; m_OPName[ 0xd5 ] = "CMP";
    m_OPFunc[ 0xd6 ] = &M6502::OP_DEC; m_OPMode[ 0xd6 ] = ZPX;    m_OPCycles[ 0xd6 ] = 6; m_OPName[ 0xd6 ] = "DEC";
    m_OPFunc[ 0xd8 ] = &M6502::OP_CLD; m_OPMode[ 0xd8 ] = IMP;    m_OPCycles[ 0xd8 ] = 2; m_OPName[ 0xd8 ] = "CLD";
    m_OPFunc[ 0xd9 ] = &M6502::OP_CMP; m_OPMode[ 0xd9 ] = ABY;    m_OPCycles[ 0xd9 ] = 4; m_OPName[ 0xd9 ] = "CMP";
    m_OPFunc[ 0xdd ] = &M6502::OP_CMP; m_OPMode[ 0xdd ] = ABX;    m_OPCycles[ 0xdd ] = 4; m_OPName[ 0xdd ] = "CMP";
    m_OPFunc[ 0xde ] = &M6502::OP_DEC; m_OPMode[ 0xde ] = ABX_NC; m_OPCycles[ 0xde ] = 7; m_OPName[ 0xde ] = "DEC";
    m_OPFunc[ 0xe0 ] = &M6502::OP_CPX; m_OPMode[ 0xe0 ] = IMM;    m_OPCycles[ 0xe0 ] = 2; m_OPName[ 0xe0 ] = "CPX";
    m_OPFunc[ 0xe1 ] = &M6502::OP_SBC; m_OPMode[ 0xe1 ] = INX;    m_OPCycles[ 0xe1 ] = 6; m_OPName[ 0xe1 ] = "SBC";
    m_OPFunc[ 0xe4 ] = &M6502::OP_CPX; m_OPMode[ 0xe4 ] = ZP;     m_OPCycles[ 0xe4 ] = 3; m_OPName[ 0xe4 ] = "CPX";
    m_OPFunc[ 0xe5 ] = &M6502::OP_SBC; m_OPMode[ 0xe5 ] = ZP;     m_OPCycles[ 0xe5 ] = 3; m_OPName[ 0xe5 ] = "SBC";
    m_OPFunc[ 0xe6 ] = &M6502::OP_INC; m_OPMode[ 0xe6 ] = ZP;     m_OPCycles[ 0xe6 ] = 5; m_OPName[ 0xe6 ] = "INC";
    m_OPFunc[ 0xe8 ] = &M6502::OP_INX; m_OPMode[ 0xe8 ] = IMP;    m_OPCycles[ 0xe8 ] = 2; m_OPName[ 0xe8 ] = "INX";
    m_OPFunc[ 0xe9 ] = &M6502::OP_SBC; m_OPMode[ 0xe9 ] = IMM;    m_OPCycles[ 0xe9 ] = 2; m_OPName[ 0xe9 ] = "SBC";
    m_OPFunc[ 0xea ] = &M6502::OP_NOP; m_OPMode[ 0xea ] = IMP;    m_OPCycles[ 0xea ] = 2; m_OPName[ 0xea ] = "NOP";
    m_OPFunc[ 0xec ] = &M6502::OP_CPX; m_OPMode[ 0xec ] = ABS;    m_OPCycles[ 0xec ] = 4; m_OPName[ 0xec ] = "CPX";
    m_OPFunc[ 0xed ] = &M6502::OP_SBC; m_OPMode[ 0xed ] = ABS;    m_OPCycles[ 0xed ] = 4; m_OPName[ 0xed ] = "SBC";
    m_OPFunc[ 0xee ] = &M6502::OP_INC; m_OPMode[ 0xee ] = ABS;    m_OPCycles[ 0xee ] = 6; m_OPName[ 0xee ] = "INC";
    m_OPFunc[ 0xf0 ] = &M6502::OP_BEQ; m_OPMode[ 0xf0 ] = REL;    m_OPCycles[ 0xf0 ] = 2; m_OPName[ 0xf0 ] = "BEQ";
    m_OPFunc[ 0xf1 ] = &M6502::OP_SBC; m_OPMode[ 0xf1 ] = INY;    m_OPCycles[ 0xf1 ] = 5; m_OPName[ 0xf1 ] = "SBC";
    m_OPFunc[ 0xf5 ] = &M6502::OP_SBC; m_OPMode[ 0xf5 ] = ZPX;    m_OPCycles[ 0xf5 ] = 4; m_OPName[ 0xf5 ] = "SBC";
    m_OPFunc[ 0xf6 ] = &M6502::OP_INC; m_OPMode[ 0xf6 ] = ZPX;    m_OPCycles[ 0xf6 ] = 6; m_OPName[ 0xf6 ] = "INC";
    m_OPFunc[ 0xf8 ] = &M6502::OP_SED; m_OPMode[ 0xf8 ] = IMP;    m_OPCycles[ 0xf8 ] = 2; m_OPName[ 0xf8 ] = "SED";
    m_OPFunc[ 0xf9 ] = &M6502::OP_SBC; m_OPMode[ 0xf9 ] = ABY;    m_OPCycles[ 0xf9 ] = 4; m_OPName[ 0xf9 ] = "SBC";
    m_OPFunc[ 0xfd ] = &M6502::OP_SBC; m_OPMode[ 0xfd ] = ABX;    m_OPCycles[ 0xfd ] = 4; m_OPName[ 0xfd ] = "SBC";
    m_OPFunc[ 0xfe ] = &M6502::OP_INC; m_OPMode[ 0xfe ] = ABX_NC; m_OPCycles[ 0xfe ] = 7; m_OPName[ 0xfe ] = "INC";
}

////////////////////////////////////////////////////////////////////////////////////////////////////

M6502::~M6502() {}

////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned char M6502::Fetch() {
    return m_Read( m_PC.W++ );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned char M6502::Peek( int offset ) {
    return m_Read( (m_PC.W + offset) & 0xffff );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::HandleNMI() {
    // FIXME
    //printf("\nNMI"); getch();

    StackPush( m_PC.H );
    StackPush( m_PC.L );
    StackPush( (JoinFlags() | 0x20) & 0xff );
    m_Flag.I = true;
    m_PC.H = m_Read( 0xfffb );
    m_PC.L = m_Read( 0xfffa );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::StackPush( unsigned char value ) {
    m_Write( (m_SP-- | 0x0100) & 0xffff, value );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned char M6502::StackPop() {
    return m_Read( (++m_SP | 0x0100) & 0xffff );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned char M6502::JoinFlags()const {
    unsigned char f = 0;
    f |= ( (m_Flag.N ? 1 : 0) << 7 );
    f |= ( (m_Flag.V ? 1 : 0) << 6 );
    f |= ( (m_Flag.P ? 1 : 0) << 5 );
    f |= ( (m_Flag.B ? 1 : 0) << 4 );
    f |= ( (m_Flag.D ? 1 : 0) << 3 );
    f |= ( (m_Flag.I ? 1 : 0) << 2 );
    f |= ( (m_Flag.Z ? 1 : 0) << 1 );
    f |= ( m_Flag.C ? 1 : 0 );

    return ( f & 0xff );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

int M6502::Execute( unsigned char opcode ) {
    if( ! m_OPFunc.count(opcode) ) {
        printf( "\nERROR: < %02X > no es un opcode valido", opcode );
        getchar();
        exit( 0 );
    }

    #ifdef DEBUG
    char d[100];
    Debug( d, m_OPMode.at(opcode), m_OPName.at(opcode) );
    printf( "\n%04X  %02X %s", (m_PC.W - 1) & 0xffff, opcode, d );
    #endif

    ( this->*m_OPFunc.at(opcode) )( m_OPMode.at(opcode) );

    #ifdef NESTEST
    m_Cycles += ( m_OPCycles.at(opcode) * TIME_BASE );
    if( m_Cycles >= 341 ) m_Cycles -= 341;
    #endif

    return m_OPCycles.at( opcode );

    return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::Debug( char output[], int mode, std::string name ) {
    switch( mode ) {
        case ACC: {
            sprintf( output, "       %s A                           ", name.c_str() );
        } break;

        case ABS: {
            unsigned char op1 = Peek( 0 );
            unsigned char op2 = Peek( 1 );
            if( ! ((name.compare("JMP") == 0) || (name.compare("JSR") == 0)) ) {
                sprintf( output, "%02X %02X  %s $%02X%02X = %02X                  ", op1, op2, name.c_str(), op2, op1, m_Read(((op2 << 8) | op1) & 0xffff) );
            } else {
                sprintf( output, "%02X %02X  %s $%02X%02X                       ", op1, op2, name.c_str(), op2, op1 );
            }
        } break;

        case ABX:
        case ABX_NC: {
            unsigned char op1 = Peek( 0 );
            unsigned char op2 = Peek( 1 );
            sprintf( output, "%02X %02X  %s $%02X%02X,X @ %04X = %02X         ", op1, op2, name.c_str(), op2, op1, (((op2 << 8) | op1) + m_Reg.X) & 0xffff, m_Read((((op2 << 8) | op1) + m_Reg.X) & 0xffff) );
        } break;

        case ABY:
        case ABY_NC: {
            unsigned char op1 = Peek( 0 );
            unsigned char op2 = Peek( 1 );
            sprintf( output, "%02X %02X  %s $%02X%02X,Y @ %04X = %02X         ", op1, op2, name.c_str(), op2, op1, (((op2 << 8) | op1) + m_Reg.Y) & 0xffff, m_Read((((op2 << 8) | op1) + m_Reg.Y) & 0xffff) );
        } break;

        case IMM: {
            unsigned char op1 = Peek( 0 );
            sprintf( output, "%02X     %s #$%02X                        ", op1, name.c_str(), op1 );
        } break;

        case IMP: {
            sprintf( output, "       %s                             ", name.c_str() );
        } break;

        case IND: {
            unsigned char op1 = Peek( 0 );
            unsigned char op2 = Peek( 1 );
            sprintf( output, "%02X %02X  %s ($%02X%02X) = %02X%02X              ", op1, op2, name.c_str(), op2, op1, m_Read(((op2 << 8) | (op1 + 1)) & 0xffff), m_Read(((op2 << 8) | op1) & 0xffff) );
        } break;

        case INX: {
            unsigned char op1 = Peek( 0 );
            sprintf( output, "%02X     %s ($%02X,X) @ %02X = %02X%02X = %02X    ", op1, name.c_str(), op1, (op1 + m_Reg.X) & 0xff, m_Read((op1 + m_Reg.X + 1) & 0xff), m_Read((op1 + m_Reg.X) & 0xff), m_Read(((m_Read((op1 + m_Reg.X + 1) & 0xff) << 8) | m_Read((op1 + m_Reg.X) & 0xff)) & 0xffff) );
        } break;

        case INY:
        case INY_NC: {
            unsigned char op1 = Peek( 0 );
            sprintf( output, "%02X     %s ($%02X),Y = %02X%02X @ %04X = %02X  ", op1, name.c_str(), op1, m_Read((op1 + 1) & 0xff), m_Read(op1), (((m_Read((op1 + 1) & 0xff) << 8) | m_Read(op1)) + m_Reg.Y) & 0xffff, m_Read((((m_Read((op1 + 1) & 0xff) << 8) | m_Read(op1)) + m_Reg.Y) & 0xffff) );
        } break;

        case REL: {
            unsigned char op1 = Peek( 0 );
            sprintf( output, "%02X     %s $%04X                       ", op1, name.c_str(), (m_PC.W + op1 + 1) & 0xffff );
        } break;

        case ZP: {
            unsigned char op1 = Peek( 0 );
            sprintf( output, "%02X     %s $%02X = %02X                    ", op1, name.c_str(), op1, m_Read(op1) );
        } break;

        case ZPX: {
            unsigned char op1 = Peek( 0 );
            sprintf( output, "%02X     %s $%02X,X @ %02X = %02X             ", op1, name.c_str(), op1, (op1 + m_Reg.X) & 0xff, m_Read((op1 + m_Reg.X) & 0xff) );
        } break;

        case ZPY: {
            unsigned char op1 = Peek( 0 );
            sprintf( output, "%02X     %s $%02X,Y @ %02X = %02X             ", op1, name.c_str(), op1, (op1 + m_Reg.Y) & 0xff, m_Read((op1 + m_Reg.Y) & 0xff) );
        } break;
    }

    char status[100];
    sprintf( status, "A:%02X X:%02X Y:%02X P:%02X SP:%02X CYC:%3i", m_Reg.A, m_Reg.X, m_Reg.Y, JoinFlags(), m_SP, m_Cycles );

    strcat( output, status );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

unsigned short M6502::SolveAddress( int mode ) {
    switch( mode ) {
        case ABS: {
            unsigned short t = ( (Fetch() | (Fetch() << 8)) & 0xffff );
            return t;
        }

        case ABX: {
            PAIR_REGISTER t;
            t.L = Fetch();
            t.H = Fetch();
            unsigned char b = t.H;
            t.W += m_Reg.X;
            if( b != t.H ) m_Cycles += ( 1 * TIME_BASE );
            return t.W;
        }

        case ABX_NC: {
            PAIR_REGISTER t;
            t.L = Fetch();
            t.H = Fetch();
            t.W += m_Reg.X;
            return t.W;
        }

        case ABY: {
            PAIR_REGISTER t;
            t.L = Fetch();
            t.H = Fetch();
            unsigned char b = t.H;
            t.W += m_Reg.Y;
            if( b != t.H ) m_Cycles += ( 1 * TIME_BASE );
            return t.W;
        }

        case ABY_NC: {
            PAIR_REGISTER t;
            t.L = Fetch();
            t.H = Fetch();
            t.W += m_Reg.Y;
            return t.W;
        }

        case IMM: {
            return m_PC.W++;
        }

        case IND: {
            PAIR_REGISTER t1, t2;
            t1.L = Fetch();
            t1.H = m_Read( m_PC.W );
            t2.L = m_Read( t1.W );
            t1.L++;
            t2.H = m_Read( t1.W );
            return t2.W;
        }

        case INX: {
            PAIR_REGISTER t;
            t.L = m_Read( (m_Read(m_PC.W) + m_Reg.X) & 0xff );
            t.H = m_Read( (Fetch() + m_Reg.X + 1) & 0xff );
            return t.W;
        }

        case INY: {
            PAIR_REGISTER t;
            t.L = m_Read( m_Read(m_PC.W) );
            t.H = m_Read( (Fetch() + 1) & 0xff );
            unsigned char b = t.H;
            t.W = ( (((t.H << 8) | t.L) + m_Reg.Y) & 0xffff );
            if( b != t.H ) m_Cycles += ( 1 * TIME_BASE );
            return t.W;
        }

        case INY_NC: {
            PAIR_REGISTER t;
            t.L = m_Read( m_Read(m_PC.W) );
            t.H = m_Read( (Fetch() + 1) & 0xff );
            t.W = ( (((t.H << 8) | t.L) + m_Reg.Y) & 0xffff );
            return t.W;
        }

        case REL: {
            unsigned char b = ( (((m_PC.W + 1) & 0xffff) >> 8) & 0xff );
            signed short d = Fetch();
            if( TestBit(d, 7) ) d -= 0x0100;
            m_PC.W = ( (m_PC.W + d) & 0xffff );
            m_Cycles += ( b != m_PC.H ? 2 : 1 ) * TIME_BASE;
            return m_PC.W;
        }

        case ZP: {
            return Fetch();
        }

        case ZPX: {
            return ( (Fetch() + m_Reg.X) & 0x00ff );
        }

        case ZPY: {
            return ( (Fetch() + m_Reg.Y) & 0x00ff );
        }
    }

    return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_ADC( int mode ) {
    unsigned char t = m_Read( SolveAddress(mode) );
    unsigned short r = ( (m_Reg.A + t + (m_Flag.C ? 1 : 0)) & 0xffff );
    m_Flag.C = ( r > 0x00ff );
    bool c1 = TestBit( (m_Reg.A ^ t) & 0xff, 7 );
    bool c2 = TestBit( (m_Reg.A ^ (r & 0x00ff)) & 0xff, 7 );
    m_Flag.V = ( (! c1) && c2 );
    m_Reg.A = ( r & 0xff );
    m_Flag.Z = ( m_Reg.A == 0 );
    m_Flag.N = TestBit( m_Reg.A, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_AND( int mode ) {
    m_Reg.A &= m_Read( SolveAddress(mode) );
    m_Flag.Z = ( m_Reg.A == 0 );
    m_Flag.N = TestBit( m_Reg.A, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_ASL( int mode ) {
    unsigned short a = 0;
    unsigned char t = 0;
    if( mode == ACC ) {
        t = m_Reg.A;
    } else {
        a = SolveAddress( mode );
        t = m_Read( a );
    }
    m_Flag.C = TestBit( t, 7 );
    t = ( (t << 1) & 0xfe );
    m_Flag.Z = ( t == 0 );
    m_Flag.N = TestBit( t, 7 );
    if( mode == ACC ) {
        m_Reg.A = t;
    } else {
        m_Write( a, t );
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_BIT( int mode ) {
    unsigned char t = m_Read( SolveAddress(mode) );
    m_Flag.Z = ( (t & m_Reg.A) == 0 );
    m_Flag.V = TestBit( t, 6 );
    m_Flag.N = TestBit( t, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_BCC( int mode ) {
    if( ! m_Flag.C )  m_PC.W = SolveAddress( mode );
    else            m_PC.W++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_BCS( int mode ) {
    if( m_Flag.C )  m_PC.W = SolveAddress( mode );
    else            m_PC.W++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_BEQ( int mode ) {
    if( m_Flag.Z )  m_PC.W = SolveAddress( mode );
    else            m_PC.W++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_BMI( int mode ) {
    if( m_Flag.N )  m_PC.W = SolveAddress( mode );
    else            m_PC.W++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_BNE( int mode ) {
    if( ! m_Flag.Z )  m_PC.W = SolveAddress( mode );
    else            m_PC.W++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_BPL( int mode ) {
    if( ! m_Flag.N )  m_PC.W = SolveAddress( mode );
    else            m_PC.W++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_BVC( int mode ) {
    if( ! m_Flag.V )  m_PC.W = SolveAddress( mode );
    else            m_PC.W++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_BVS( int mode ) {
    if( m_Flag.V )  m_PC.W = SolveAddress( mode );
    else            m_PC.W++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_CLC( int mode ) {
    m_Flag.C = 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_CLD( int mode ) {
    m_Flag.D = 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_CLI( int mode ) {
    m_Flag.I = 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_CLV( int mode ) {
    m_Flag.V = 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_CMP( int mode ) {
    unsigned char t = m_Read( SolveAddress(mode) );
    unsigned char r = ( (m_Reg.A - t) & 0xff );
    m_Flag.C = ( m_Reg.A >= t );
    m_Flag.Z = ( m_Reg.A == t );
    m_Flag.N = TestBit( r, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_CPX( int mode ) {
    unsigned char t = m_Read( SolveAddress(mode) );
    unsigned char r = ( (m_Reg.X - t) & 0xff );
    m_Flag.C = ( m_Reg.X >= t );
    m_Flag.Z = ( m_Reg.X == t );
    m_Flag.N = TestBit( r, 7 );
}


////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_CPY( int mode ) {
    unsigned char t = m_Read( SolveAddress(mode) );
    unsigned char r = ( (m_Reg.Y - t) & 0xff );
    m_Flag.C = ( m_Reg.Y >= t );
    m_Flag.Z = ( m_Reg.Y == t );
    m_Flag.N = TestBit( r, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_DEC( int mode ) {
    unsigned short a = SolveAddress( mode );
    unsigned char t = m_Read( a );
    t--;
    m_Write( a, t );
    m_Flag.Z = ( t == 0 );
    m_Flag.N = TestBit( t, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_DEX( int mode ) {
    m_Reg.X--;
    m_Flag.Z = ( m_Reg.X == 0 );
    m_Flag.N = TestBit( m_Reg.X, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_DEY( int mode ) {
    m_Reg.Y--;
    m_Flag.Z = ( m_Reg.Y == 0 );
    m_Flag.N = TestBit( m_Reg.Y, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_EOR( int mode ) {
    m_Reg.A ^= m_Read( SolveAddress(mode) );
    m_Flag.Z = ( m_Reg.A == 0 );
    m_Flag.N = TestBit( m_Reg.A, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_INC( int mode ) {
    unsigned short a = SolveAddress( mode );
    unsigned char t = m_Read( a );
    t++;
    m_Write( a, t );
    m_Flag.Z = ( t == 0 );
    m_Flag.N = TestBit( t, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_INX( int mode ) {
    m_Reg.X++;
    m_Flag.Z = ( m_Reg.X == 0 );
    m_Flag.N = TestBit( m_Reg.X, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_INY( int mode ) {
    m_Reg.Y++;
    m_Flag.Z = ( m_Reg.Y == 0 );
    m_Flag.N = TestBit( m_Reg.Y, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_JMP( int mode ) {
    m_PC.W = SolveAddress( mode );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_JSR( int mode ) {
    PAIR_REGISTER t = m_PC;
    t.W++;
    StackPush( t.H );
    StackPush( t.L );

    m_PC.W = SolveAddress( mode );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_LDA( int mode ) {
    m_Reg.A = m_Read( SolveAddress(mode) );
    m_Flag.Z = ( m_Reg.A == 0 );
    m_Flag.N = TestBit( m_Reg.A, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_LDX( int mode ) {
    m_Reg.X = m_Read( SolveAddress(mode) );
    m_Flag.Z = ( m_Reg.X == 0 );
    m_Flag.N = TestBit( m_Reg.X, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_LDY( int mode ) {
    m_Reg.Y = m_Read( SolveAddress(mode) );
    m_Flag.Z = ( m_Reg.Y == 0 );
    m_Flag.N = TestBit( m_Reg.Y, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_LSR( int mode ) {
    unsigned short a = 0;
    unsigned char t = 0;
    if( mode == ACC ) {
        t = m_Reg.A;
    } else {
        a = SolveAddress( mode );
        t = m_Read( a );
    }
    m_Flag.N = false;
    m_Flag.C = TestBit( t, 0 );
    t = ( (t >> 1) & 0x7f );
    m_Flag.Z = ( t == 0 );
    if( mode == ACC ) {
        m_Reg.A = t;
    } else {
        m_Write( a, t );
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_NOP( int mode ) {
    return;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_PHA( int mode ) {
    StackPush( m_Reg.A );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_ORA( int mode ) {
    m_Reg.A |= m_Read( SolveAddress(mode) );
    m_Flag.Z = ( m_Reg.A == 0 );
    m_Flag.N = TestBit( m_Reg.A, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_PHP( int mode ) {
    StackPush( (JoinFlags() | 0x30) & 0xff );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_PLA( int mode ) {
    m_Reg.A = StackPop();
    m_Flag.Z = ( m_Reg.A == 0 );
    m_Flag.N = TestBit( m_Reg.A, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_PLP( int mode ) {
    unsigned char t = StackPop();
    m_Flag.P = true;
    m_Flag.B = false;
    m_Flag.N = TestBit( t, 7 );
    m_Flag.V = TestBit( t, 6 );
    m_Flag.D = TestBit( t, 3 );
    m_Flag.I = TestBit( t, 2 );
    m_Flag.Z = TestBit( t, 1 );
    m_Flag.C = TestBit( t, 0 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_ROL( int mode ) {
    unsigned short a = 0;
    unsigned char t = 0;
    if( mode == ACC ) {
        t = m_Reg.A;
    } else {
        a = SolveAddress( mode );
        t = m_Read( a );
    }
    bool c = m_Flag.C;
    m_Flag.C = TestBit( t, 7 );
    t = ( (t << 1) & 0xfe );
    if( c ) t = ( (t | 0x01) & 0xff );
    m_Flag.N = TestBit( t, 7 );
    m_Flag.Z = ( t == 0 );
    if( mode == ACC ) {
        m_Reg.A = t;
    } else {
        m_Write( a, t );
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_ROR( int mode ) {
    unsigned short a = 0;
    unsigned char t = 0;
    if( mode == ACC ) {
        t = m_Reg.A;
    } else {
        a = SolveAddress( mode );
        t = m_Read( a );
    }
    bool c = m_Flag.C;
    m_Flag.C = TestBit( t, 0 );
    t = ( (t >> 1) & 0x7e );
    if( c ) t = ( (t | 0x80) & 0xff );
    m_Flag.N = TestBit( t, 7 );
    m_Flag.Z = ( t == 0 );
    if( mode == ACC ) {
        m_Reg.A = t;
    } else {
        m_Write( a, t );
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_RTI( int mode ) {
    unsigned char t = StackPop();
    m_Flag.P = true;
    m_Flag.B = false;
    m_Flag.N = TestBit( t, 7 );
    m_Flag.V = TestBit( t, 6 );
    m_Flag.D = TestBit( t, 3 );
    m_Flag.I = TestBit( t, 2 );
    m_Flag.Z = TestBit( t, 1 );
    m_Flag.C = TestBit( t, 0 );
    m_PC.L = StackPop();
    m_PC.H = StackPop();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_RTS( int mode ) {
    m_PC.L = StackPop();
    m_PC.H = StackPop();
    m_PC.W++;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_SBC( int mode ) {
    unsigned char t = m_Read( SolveAddress(mode) );
    unsigned short r = ( (m_Reg.A - t - (1 - (m_Flag.C ? 1 : 0))) & 0xffff );
    m_Flag.C = ( r < 0x0100 );
    bool c1 = TestBit( (m_Reg.A ^ t) & 0xff, 7 );
    bool c2 = TestBit( (m_Reg.A ^ (r & 0x00ff)) & 0xff, 7 );
    m_Flag.V = ( c1 && c2 );
    m_Reg.A = ( r & 0xff );
    m_Flag.Z = ( m_Reg.A == 0 );
    m_Flag.N = TestBit( m_Reg.A, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_SEC( int mode ) {
    m_Flag.C = true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_SED( int mode ) {
    m_Flag.D = true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_SEI( int mode ) {
    m_Flag.I = true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_STX( int mode ) {
    m_Write( SolveAddress(mode), m_Reg.X );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_STY( int mode ) {
    m_Write( SolveAddress(mode), m_Reg.Y );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_STA( int mode ) {
    m_Write( SolveAddress(mode), m_Reg.A );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_TAX( int mode ) {
    m_Reg.X = m_Reg.A;
    m_Flag.Z = ( m_Reg.X == 0 );
    m_Flag.N = TestBit( m_Reg.X, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_TAY( int mode ) {
    m_Reg.Y = m_Reg.A;
    m_Flag.Z = ( m_Reg.Y == 0 );
    m_Flag.N = TestBit( m_Reg.Y, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_TSX( int mode ) {
    m_Reg.X = m_SP;
    m_Flag.Z = ( m_Reg.X == 0 );
    m_Flag.N = TestBit( m_Reg.X, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_TXA( int mode ) {
    m_Reg.A = m_Reg.X;
    m_Flag.Z = ( m_Reg.A == 0 );
    m_Flag.N = TestBit( m_Reg.A, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_TXS( int mode ) {
    m_SP = m_Reg.X;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void M6502::OP_TYA( int mode ) {
    m_Reg.A = m_Reg.Y;
    m_Flag.Z = ( m_Reg.A == 0 );
    m_Flag.N = TestBit( m_Reg.A, 7 );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
